package com.shy.collect.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shy.collect.entity.PmsMenu;
import com.shy.collect.entity.PmsOperator;
import com.shy.collect.mapper.PmsMenuMapper;
import com.shy.collect.mapper.PmsOperatorMapper;
import com.shy.collect.service.OperatorService;
import com.shy.configs.common.clients.RedisClient;
import com.shy.configs.common.consts.Keys;
import com.shy.configs.common.enums.RCode;
import com.shy.configs.common.exceptions.DftException;
import com.shy.configs.common.utils.JWTUtils;
import com.shy.configs.mvc.models.dto.OperatorLoginDto;
import com.shy.configs.mvc.models.menus.MenuItem;
import com.shy.configs.mvc.models.menus.SubMenu;
import com.shy.configs.mvc.models.query.OperatorLoginQuery;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class OperatorServiceImpl implements OperatorService {
    @Resource
    private PmsOperatorMapper pmsOperatorMapper;
    @Resource
    private RedisClient redisClient;
    @Resource
    private PmsMenuMapper pmsMenuMapper;

    private final Object objectLock = new Object();

    @Override
    public OperatorLoginDto login(OperatorLoginQuery loginQuery) {
        //访问数据库查询用户是否存在
        QueryWrapper<PmsOperator> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("login_name", loginQuery.getLoginName());
        PmsOperator pmsOperator = pmsOperatorMapper.selectOne(queryWrapper);
        if (pmsOperator == null) {
            //用户不存在
            throw new DftException(RCode.FAIL_USER_NUll);
        }
        String salt = pmsOperator.getSalt();
        //计算密码
        String pwd = DigestUtil.md5Hex(loginQuery.getLoginPwd() + salt);
        if (!pwd.equals(pmsOperator.getLoginPwd())) {
            // 密码不正确
            throw new DftException(RCode.FAIL_USER_NOT_EXIST);
        }
        // 登录成功生成jwt
        String jwt = JWTUtils.createJWT(String.valueOf(pmsOperator.getId()), 60 * 60 * 4);
        //存储到redis
        Map<String, String> data = new HashMap<>();
        data.put("loginId", String.valueOf(pmsOperator.getId()));
        data.put("jwt", jwt);
        data.put("loginTime", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        String tokenKey = Keys.LOGIN_TOKEN_KEY + pmsOperator.getId();
        redisClient.setHashValue(tokenKey, data, 60 * 60 * 4, TimeUnit.MINUTES);

        // 返回数据给前端
        OperatorLoginDto operatorLoginDto = new OperatorLoginDto(pmsOperator.getId(), pmsOperator.getShowName(), jwt);

        return operatorLoginDto;

    }

    /**
     * 查询菜单
     *
     * @param operatorId
     * @return
     */
    @Override
    public List<SubMenu> queryMenuByOperatorId(Long operatorId) {
        List<SubMenu> subMenuList = new ArrayList<>();

        String key = Keys.OPERATOR_MENUS + operatorId;
        try {
            // 从缓存中获取菜单
            String menuJsonText = redisClient.getValue(key);
            if (StrUtil.isNotBlank(menuJsonText)) {
                subMenuList = JSONUtil.toList(menuJsonText, SubMenu.class);
            } else {
                synchronized (objectLock) {
                    if (StrUtil.isNotBlank(menuJsonText)) {
                        subMenuList = JSONUtil.toList(menuJsonText, SubMenu.class);
                    } else {
                        // 从数据库中获取菜单
                        subMenuList = getSubMenus(operatorId);
                        if (!subMenuList.isEmpty()) {
                            // 将菜单写入缓存
                            redisClient.setValue(key, JSONUtil.toJsonStr(subMenuList));
                        }
                    }
                }
            }
        } catch (Exception e) {
            subMenuList = getSubMenus(operatorId);
        }
        return subMenuList;
    }

    @Override
    public boolean logout(Long operatorId) {
        // 删除redis中的token
        String tokenKey = Keys.LOGIN_TOKEN_KEY + operatorId;
        return redisClient.deleteKey(tokenKey);
    }

    /**
     * 从数据库获取菜单
     *
     * @param operatorId
     * @return
     */
    private List<SubMenu> getSubMenus(Long operatorId) {
        List<SubMenu> subMenus = new ArrayList<>();
        // 调用mapper查询菜单
        List<PmsMenu> pmsMenus = pmsMenuMapper.selectSubMenuByUserId(operatorId);
        //查询角色对应的菜单
        for (PmsMenu pMenu : pmsMenus) {
            SubMenu subMenu = new SubMenu();
            subMenu.setId(pMenu.getId());
            subMenu.setName(pMenu.getName());
            subMenu.setUrl(pMenu.getUrl());
            subMenu.setNumber(pMenu.getNumber());

            List<PmsMenu> itemMenus = pmsMenuMapper.selectItemMenuByRoleId(pMenu.getId());
            itemMenus.forEach(itemMenu -> {
                MenuItem item = new MenuItem();
                item.setId(itemMenu.getId());
                item.setName(itemMenu.getName());
                item.setUrl(itemMenu.getUrl());
                item.setNumber(itemMenu.getNumber());

                subMenu.getItems().add(item);
            });
            subMenus.add(subMenu);
        }
        return subMenus;
    }
}